# The Store

import index from '!!raw-loader!@site/docs/examples/store.ex';
import { LiveDemo } from '@site/components/LiveDemo';

The `createStore` function is used to initialize a store with a state.
The first argument is a configuration object where a name of the store is specified.
After the first argument any number of features can be specified which describe the nature of the store.

An example of a simple store:

```ts
import { createStore, withProps } from '@ngneat/elf';

interface AuthProps {
  user: { id: string } | null;
}

const authStore = createStore(
  { name: 'auth' },
  withProps<AuthProps>({ user: null }),
);
```

An example of a store that contains multiple state features:

```ts
const store = createStore(
  { name: 'todo' },
  withEntities<Todo>(),
  withUIEntities<UIEntity>(),
  withProps<{ foo: string }>({ foo: '' }),
);
```

The features can be either one or more of the available features in Elf, or additional features you can create or add from other sources.

## Querying the Store

A store is a `BehaviorSubject`. Therefore, we can subscribe to it to get its initial value and its subsequent values:

```ts
authStore.subscribe((state) => {
  console.log(state);
});
```

### The `select` operator

Select a slice from the store:

```ts
import { select } from '@ngneat/elf';

const user$ = authStore.pipe(select((state) => state.user));
```

The `select()` operator returns an observable that calls `distinctUntilChanged()` internally, meaning it will only fire when the state changes, i.e., when there is a new reference to the selected state.

We can also query its value **once** without the need to subscribe:

```ts
const state = authstore.getValue();
```

## Updating the Store

To update the store, we can use the `update` method which receives a callback function, which gets the current `state`, and returns a new **immutable** `state`, which will be the new value of the store:

```ts
authStore.update((state) => ({
  ...state,
  user: { id: 'foo' },
}));
```

### Updating a root property

```ts
import { setProp, setProps } from '@ngneat/elf';

store.update(setProp('foo', 'bar'));
store.update(setProp('count', (count) => count + 1));

store.update(
  setProps({
    count: 1,
    child: 2,
  }),
);

store.update(
  setProps((state) => ({
    count: 1,
    nested: {
      ...state.nested,
      bar: 'baz',
    },
  })),
);
```

<LiveDemo src={index} />
